package com.example.demo.security;

import com.example.demo.exception.UnauthorizedException;
import com.example.demo.model.entity.user.User;
import io.jsonwebtoken.Claims;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Optional;

/**
 * 安全工具类
 * 提供获取当前认证用户信息的方法
 */
@Component
public class SecurityUtils {

    /**
     * 获取当前认证信息
     * @throws UnauthorizedException 如果用户未认证
     */
    private Authentication getAuthentication() {
        return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
                .filter(Authentication::isAuthenticated)
                .orElseThrow(() -> new UnauthorizedException("用户未认证"));
    }

    /**
     * 获取当前登录用户的用户名
     * @return 当前用户名
     * @throws UnauthorizedException 如果用户未认证
     */
    public String getCurrentUsername() {
        return getAuthentication().getName();
    }

    /**
     * 获取当前登录用户的ID
     * @return 当前用户ID
     * @throws UnauthorizedException 如果用户未认证或用户ID无法获取
     */
    public Long getCurrentUserId() {
        Object principal = getAuthentication().getPrincipal();

        try {
            if (principal instanceof UserDetailsImpl) {
                return ((UserDetailsImpl) principal).getUser().getId();
            } else if (principal instanceof Claims) {
                return ((Claims) principal).get("userId", Long.class);
            } else if (principal instanceof Map) {
                return parseUserIdFromMap((Map<?, ?>) principal);
            } else if (principal instanceof String) {
                throw new UnauthorizedException("无法从用户名获取用户ID");
            }
            throw new UnauthorizedException("不支持的认证主体类型: " + principal.getClass().getName());
        } catch (Exception e) {
            throw new UnauthorizedException("获取用户ID失败: " + e.getMessage(), e);
        }
    }

    private Long parseUserIdFromMap(Map<?, ?> claims) {
        Object userId = claims.get("userId");
        if (userId == null) {
            throw new UnauthorizedException("JWT claims 中缺少 userId 字段");
        }

        if (userId instanceof Long) {
            return (Long) userId;
        } else if (userId instanceof Integer) {
            return ((Integer) userId).longValue();
        } else if (userId instanceof String) {
            try {
                return Long.parseLong((String) userId);
            } catch (NumberFormatException e) {
                throw new UnauthorizedException("用户ID格式错误: " + userId);
            }
        }
        throw new UnauthorizedException("不支持的userId类型: " + userId.getClass().getName());
    }

    /**
     * 获取当前用户完整信息
     * @return User实体对象
     * @throws UnauthorizedException 如果无法获取用户信息
     */
    public User getCurrentUser() {
        Object principal = getAuthentication().getPrincipal();

        if (principal instanceof UserDetailsImpl) {
            return ((UserDetailsImpl) principal).getUser();
        } else if (principal instanceof Claims) {
            return buildUserFromClaims((Claims) principal);
        }
        throw new UnauthorizedException("无法从类型 [" + principal.getClass().getName() + "] 获取用户信息");
    }

    private User buildUserFromClaims(Claims claims) {
        User user = new User();
        user.setId(claims.get("userId", Long.class));
        user.setUsername(claims.getSubject());
        // 根据需要设置其他字段
        return user;
    }

    /**
     * 检查当前用户是否具有指定角色
     * @param role 要检查的角色（格式如 "ROLE_ADMIN"）
     * @return 是否具有该角色
     */
    public boolean hasRole(String role) {
        return getAuthentication().getAuthorities().stream()
                .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(role));
    }

    /**
     * 检查当前用户是否具有任一指定角色
     * @param roles 要检查的角色数组
     * @return 是否具有任一角色
     */
    public boolean hasAnyRole(String... roles) {
        return getAuthentication().getAuthorities().stream()
                .anyMatch(grantedAuthority -> {
                    String authority = grantedAuthority.getAuthority();
                    for (String role : roles) {
                        if (authority.equals(role)) {
                            return true;
                        }
                    }
                    return false;
                });
    }
}